/*
 * Copyright (C) 2006-2010 - Frictional Games
 *
 * This file is part of HPL1 Engine.
 *
 * HPL1 Engine is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * HPL1 Engine is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with HPL1 Engine.  If not, see <http://www.gnu.org/licenses/>.
 */
#ifndef HPL_WORLD3D_H
#define HPL_WORLD3D_H

#include "system/SystemTypes.h"
#include "graphics/GraphicsTypes.h"
#include "math/MathTypes.h"

#include "scene/SoundSource.h"
#include "scene/Entity3D.h"

#include "game/GameTypes.h"

#include "game/SaveGame.h"

class TiXmlElement;

namespace hpl {

	class cGraphics;
	class cResources;
	class cSound;
	class cPhysics;
	class cScene;
	class cSystem;
	class cAI;
	class cHaptic;

	class iCamera;
	class cCamera3D;
	class cNode3D;
	class cLight3DSpot;
	class cLight3DPoint;
	class iLight3D;
	class cImageEntity;
	class cParticleManager;
	class cParticleSystem3D;
	class iScript;
	class cPortalContainer;
	class iRenderableContainer;
	class cMeshEntity;
	class cMesh;
	class cBillboard;
	class cBeam;
	class iPhysicsWorld;
	class cColliderEntity;
	class iPhysicsBody;
	class cSoundEntity;
	class cAINodeContainer;
	class cAStarHandler;
	class cAINodeGeneratorParams;

	typedef std::list<iLight3D*> tLight3DList;
	typedef std::list<iLight3D*>::iterator tLight3DListIt;

	typedef std::list<cMeshEntity*> tMeshEntityList;
	typedef std::list<cMeshEntity*>::iterator tMeshEntityListIt;

	typedef std::list<cBillboard*> tBillboardList;
	typedef std::list<cBillboard*>::iterator tBillboardListIt;

	typedef std::list<cBeam*> tBeamList;
	typedef std::list<cBeam*>::iterator tBeamListIt;

	typedef std::list<cParticleSystem3D*> tParticleSystem3DList;
	typedef tParticleSystem3DList::iterator tParticleSystem3DListIt;

	typedef std::list<cColliderEntity*> tColliderEntityList;
	typedef std::list<cColliderEntity*>::iterator tColliderEntityListIt;

	typedef std::list<cSoundEntity*> tSoundEntityList;
	typedef std::list<cSoundEntity*>::iterator tSoundEntityListIt;

	typedef std::list<cAINodeContainer*> tAINodeContainerList;
	typedef std::list<cAINodeContainer*>::iterator tAINodeContainerListIt;

	typedef std::list<cAStarHandler*> tAStarHandlerList;
	typedef std::list<cAStarHandler*>::iterator tAStarHandlerIt;

	//-------------------------------------------------------------------

	typedef cSTLIterator<cMeshEntity*, tMeshEntityList, tMeshEntityListIt> cMeshEntityIterator;
	typedef cSTLIterator<cBillboard*, tBillboardList, tBillboardListIt> cBillboardIterator;
	typedef cSTLIterator<iLight3D*, tLight3DList, tLight3DListIt> cLight3DListIterator;
	typedef cSTLIterator<cParticleSystem3D*, tParticleSystem3DList, tParticleSystem3DListIt> cParticleSystem3DIterator;
	typedef cSTLIterator<cSoundEntity*, tSoundEntityList, tSoundEntityListIt> cSoundEntityIterator;
	typedef cSTLIterator<cBeam*, tBeamList, tBeamListIt> cBeamIterator;

	//-------------------------------------------------------------------

	class cTempAiNode
	{
	public:
		cTempAiNode(const cVector3f& avPos, const tString& asName) : mvPos(avPos),msName(asName){}
		cVector3f mvPos;
		tString msName;
	};

	typedef std::list<cTempAiNode> tTempAiNodeList;
	typedef std::list<cTempAiNode>::iterator tTempAiNodeListIt;

	class cTempNodeContainer
	{
	public:
		tString msName;
		tTempAiNodeList mlstNodes;
	};

	typedef std::map<tString,cTempNodeContainer*> tTempNodeContainerMap;
	typedef std::map<tString,cTempNodeContainer*>::iterator tTempNodeContainerMapIt;

	//-------------------------------------------------------------------

	class cAreaEntity :public iSerializable
	{
		kSerializableClassInit(cAreaEntity)
	public:
		tString msName;
		tString msType;
		cMatrixf m_mtxTransform;
		cVector3f mvSize;
	};

	typedef std::map<tString, cAreaEntity*> tAreaEntityMap;
	typedef tAreaEntityMap::iterator tAreaEntityMapIt;

	//-------------------------------------------------------------------

	class cStartPosEntity : public iSerializable
	{
		kSerializableClassInit(cStartPosEntity)
	public:
		cStartPosEntity() {}
		cStartPosEntity(const tString& asName) : msName(asName){}

		cMatrixf& GetWorldMatrix(){ return m_mtxTransform;}
		cMatrixf& GetLocalMatrix(){ return m_mtxTransform;}
		void SetMatrix(const cMatrixf& a_mtxTrans){ m_mtxTransform = a_mtxTrans;}

		tString& GetName(){ return msName;}

		cMatrixf m_mtxTransform;
		tString msName;
	};

	typedef std::list<cStartPosEntity*> tStartPosEntityList;
	typedef std::list<cStartPosEntity*>::iterator tStartPosEntityListIt;

	//------------------------------------------

	kSaveData_BaseClass(cWorld3D)
	{
		kSaveData_ClassInit(cWorld3D)
	public:
		cContainerList<cStartPosEntity> mlstStartpos;
		cContainerList<cAreaEntity> mlstAreaEntities;
		cContainerList<cScriptVar> mlstScriptVars;

		virtual iSaveObject* CreateSaveObject(cSaveObjectHandler *apSaveObjectHandler,cGame *apGame);
		virtual int GetSaveCreatePrio();
	};

	//-------------------------------------------------------------------

	class cWorld3D
	{
	public:
		cWorld3D(tString asName,cGraphics *apGraphics,cResources *apResources,cSound* apSound,
					cPhysics *apPhysics, cScene *apScene,cSystem *apSystem, cAI *apAI,
					cHaptic *apHaptic);
		~cWorld3D();

		tString GetName(){ return msName;}

		bool CreateFromFile(tString asFile);

		void SetFileName(const tString& asFile){ msFileName = asFile;}
		const tString& GetFileName(){ return msFileName;}

		void Update(float afTimeStep);

		void PreUpdate(float afTotalTime, float afTimeStep);

		cVector3f GetWorldSize(){ return mvWorldSize;}

		iScript* GetScript(){ return mpScript;}
		void SetScript(iScript* apScript){ mpScript = apScript;}

		iRenderableContainer* GetRenderContainer();
		cPortalContainer* GetPortalContainer();

		cPhysics* GetPhysics(){ return mpPhysics;}
		cResources* GetResources(){ return mpResources;}
		cSound* GetSound(){ return mpSound;}
		cSystem* GetSystem(){ return mpSystem;}
		cHaptic* GetHaptic(){ return mpHaptic;}

		iEntity3D* CreateEntity(const tString& asName, const cMatrixf &a_mtxTransform,
								const tString& asFile, bool abLoadReferences);
		/**
		 * Call this when all things have been added to set up things like physics world size.
		 **/
		void SetUpData();


		void AddSaveData(cSaveDataHandler* apHandler);

		///// PHYSICS ////////////////////////////////

		void SetPhysicsWorld(iPhysicsWorld *apWorld, bool abAutoDelete=true);
		iPhysicsWorld* GetPhysicsWorld();

		///// AREA ////////////////////////////////

		cAreaEntity* CreateAreaEntity(const tString &asName);
		cAreaEntity* GetAreaEntity(const tString &asName);
		tAreaEntityMap* GetAreaEntityMap(){return &m_mapAreaEntities;}

		///// MESH ENTITY METHODS ////////////////////

		cMeshEntity* CreateMeshEntity(const tString &asName,cMesh *apMesh, bool abAddToContainer=true);
		void DestroyMeshEntity(cMeshEntity* apMesh);
		cMeshEntity* GetMeshEntity(const tString& asName);

		cMeshEntityIterator GetMeshEntityIterator();

		void DrawMeshBoundingBoxes(const cColor &aColor, bool abStatic);

		///// LIGHT METHODS ////////////////////

		cLight3DPoint* CreateLightPoint(const tString &asName="",bool abAddToContainer=true);
		cLight3DSpot* CreateLightSpot(const tString &asName="", const tString &asGobo="",
										bool abAddToContainer=true);
		void DestroyLight(iLight3D* apLight);
		iLight3D* GetLight(const tString& asName);

		tLight3DList * GetLightList(){ return &mlstLights;}

		cLight3DListIterator GetLightIterator(){ return cLight3DListIterator(&mlstLights);}

		///// BILLBOARD METHODS ////////////////////

		cBillboard* CreateBillboard(const tString& asName, const cVector2f& avSize,
									const tString& asMaterial="",
									bool abAddToContainer=true,cMatrixf* apTransform=NULL);
		void DestroyBillboard(cBillboard* apObject);
		cBillboard* GetBillboard(const tString& asName);
		cBillboardIterator GetBillboardIterator();

		///// BEAM METHODS ////////////////////

		cBeam* CreateBeam(const tString& asName);
		void DestroyBeam(cBeam* apObject);
		cBeam* GetBeam(const tString& asName);
		cBeamIterator GetBeamIterator();

		///// PARTICLE METHODS ////////////////////

		cParticleSystem3D* CreateParticleSystem(const tString& asName,const tString& asType,
										const cVector3f& avSize,const cMatrixf& a_mtxTransform);
		void DestroyParticleSystem(cParticleSystem3D* apPS);
		cParticleSystem3D* GetParticleSystem(const tString& asName);
		bool ParticleSystemExists(cParticleSystem3D* apPS);

		cParticleSystem3DIterator GetParticleSystemIterator(){ return cParticleSystem3DIterator(&mlstParticleSystems);}

		///// COllIDER METHODS ////////////////////

		cColliderEntity* CreateColliderEntity(const tString &asName,iPhysicsBody *apBody);
		void DestroyColliderEntity(cColliderEntity* apCollider);
		cColliderEntity* GetColliderEntity(const tString& asName);

		///// SOUND ENTITY METHODS ////////////////////

		cSoundEntity* CreateSoundEntity(const tString &asName,const tString &asSoundEntity,
										bool abRemoveWhenOver);
		void DestroySoundEntity(cSoundEntity* apEntity);
		cSoundEntity* GetSoundEntity(const tString& asName);
		void DestroyAllSoundEntities();
		bool SoundEntityExists(cSoundEntity* apEntity);

		cSoundEntityIterator GetSoundEntityIterator(){ return cSoundEntityIterator(&mlstSoundEntities);}

		///// START POS ENTITY METHODS ////////////////

		cStartPosEntity* CreateStartPos(const tString &asName);
		cStartPosEntity* GetStartPosEntity(const tString &asName);
		cStartPosEntity* GetFirstStartPosEntity();

		///// AI NODE METHODS ////////////////

		void GenerateAINodes(cAINodeGeneratorParams *apParams);

		cAINodeContainer* CreateAINodeContainer(const tString &asName,
											const tString &asNodeName,
											const cVector3f &avSize,
											bool abNodeIsAtCenter,
											int alMinEdges, int alMaxEdges, float afMaxEdgeDistance,
											float afMaxHeight);

		cAStarHandler* CreateAStarHandler(cAINodeContainer* apContainer);

		void AddAINode(const tString &asName, const tString &asType, const cVector3f &avPosition);
		tTempAiNodeList* GetAINodeList(const tString &asType);


		/// NODE METHODS //////////////////////
		// Remove this for the time being, not need it seems.
		//cNode3D* GetRootNode(){ return mpRootNode; }

	private:
		iSaveData* CreateSaveData();

		//Update
		void UpdateEntities(float afTimeStep);
		void UpdateBodies(float afTimeStep);
		void UpdateParticles(float afTimeStep);
		void UpdateLights(float afTimeStep);
		void UpdateSoundEntities(float afTimeStep);

		tString msName;
		tString msFileName;
		cGraphics *mpGraphics;
		cSound* mpSound;
		cResources *mpResources;
		cPhysics *mpPhysics;
		cScene *mpScene;
		cSystem *mpSystem;
		cAI *mpAI;
		cHaptic *mpHaptic;

		iPhysicsWorld *mpPhysicsWorld;
		bool mbAutoDeletePhysicsWorld;

		cVector3f mvWorldSize;

		cPortalContainer* mpPortalContainer;

		iScript *mpScript;

		tLight3DList mlstLights;
		tMeshEntityList mlstMeshEntities;
		tBillboardList mlstBillboards;
		tBeamList mlstBeams;
		tParticleSystem3DList mlstParticleSystems;
		tColliderEntityList mlstColliders;
		tSoundEntityList mlstSoundEntities;
		tStartPosEntityList mlstStartPosEntities;
		tAreaEntityMap m_mapAreaEntities;

		tAINodeContainerList mlstAINodeContainers;
		tAStarHandlerList mlstAStarHandlers;
		tTempNodeContainerMap m_mapTempNodes;

		cNode3D* mpRootNode;

		tString msMapName;
		cColor mAmbientColor;
	};

};
#endif // HPL_WOLRD3D_H
